//
// Created by shanshi on 23/6/2025.
//
#include "memory_pool.h"
#include "../include/memory_pool.h"

#include <assert.h>

namespace memory_pool {
    void memory_pool::init(size_t size) {
        assert(size > 0);
        slot_size_ = size;
        free_list_ = nullptr;
        cur_unused_list_ = nullptr;
        first_block_ = nullptr;
        last_slot_ = nullptr;
    }
    memory_pool::memory_pool(int block_size): block_size_(block_size)
    {}
    memory_pool::~memory_pool()
    {
        slot *p = first_block_;
        while(first_block_)
        {
            slot *next = p->next;
            operator delete(reinterpret_cast<void *>(p));
            p = next;
        }
    }
    void *memory_pool::allocate()
    {
        // 首先遍历自由链表中的空闲
        slot *p = free_list_;
        if(p!=nullptr){
           {
                std::lock_guard<std::mutex> lock(mutex_for_freelist_);
                if(p!=nullptr) {
                    free_list_ = p->next;
                    return  reinterpret_cast<void *>(p);
                }
           }
        }
        slot *temp;
        {
            // 从空余的块中进行分配
            std::lock_guard<std::mutex> lock(mutex_for_block_);
            if (cur_unused_list_ >= last_slot_) {
                allocate_new_block();
            }
            temp = cur_unused_list_;
            // 因为curslot是slot*类型
            cur_unused_list_ += slot_size_ / sizeof(slot);
        }
        return temp;
    }
    void memory_pool::deallocate(void *p)
    {
        //将p加入自由链表
        if (!p) {
            return;
        }
        std::lock_guard<std::mutex> lock(mutex_for_freelist_);
        slot *temp = reinterpret_cast<slot *>(p);
        temp->next = free_list_;
        free_list_ = temp;
    }
    void memory_pool::allocate_new_block() {
        // 申请内存 并插入到内存池管理的链表
        void *new_block = operator new(slot_size_);
        reinterpret_cast<slot *>(new_block)->next = first_block_;
        first_block_ = reinterpret_cast<slot *>(new_block);

        // 计算填充到slot大小，还需要申请多大内存
        char *body = reinterpret_cast<char *>(new_block) + sizeof(slot*);
        size_t padding_size = pad_pointer(body, slot_size_);
        cur_unused_list_ = reinterpret_cast<slot*>(body + padding_size);

        last_slot_ = reinterpret_cast<slot*>(reinterpret_cast<size_t>(new_block) + block_size_);
        free_list_ = nullptr;
    }
    size_t memory_pool::pad_pointer(void* p, size_t align) {
        return (align - (reinterpret_cast<size_t>(p) % align)) % align;
    }
    void hash_bucket::init_memory_pool() {
        int i = 0;
        for (;i<MEMORY_POOL_NUM;i++) {
            memory_pool& pool = get_memory_pool(i);
            pool.init((i + 1) * SLOT_BASE_SIZE);
        }
    }

    static memory_pool &hash_bucket::get_memory_pool(size_t index) {
        static memory_pool memory_pool_array[MEMORY_POOL_NUM];
        return memory_pool_array[index];
    }

}
